export default class Bezier {
    private _posArr: { x: number, y: number }[] = []
    private _dividePaths: [[{ x, y }]]
    private _smoothness: number = 30// 平滑度 就是总长度分成多少段
    ctlPosNum = 3
    reverse = false
    bRunEnd = false
    private _time = 0
    private _pathIndex = 0

    getPos(index?) {
        let pathNum = this._dividePaths.length
        if (index == null && this._time != this._smoothness * pathNum)
            this._time++
        if (this._time > this._smoothness && this._time % this.smoothness == 1)
            this._pathIndex++
        this.bRunEnd = this._time == this._smoothness * pathNum
        let curPath = this._dividePaths[this._pathIndex]
        let time = 0
        if (index != null) {
            time = index / this._smoothness
        } else {
            time = this._time >= this.smoothness && (this._time % this.smoothness == 0) ? 1 : this._time % this.smoothness / this.smoothness
        }
        return this.bezier(curPath, time)
    }

    setPath(posArr: { x: number, y: number }[]) {
        this._time = 0
        this._pathIndex = 0
        this._posArr = posArr
        this._dividePath()
        if (this.reverse) {
            this._dividePaths.reverse()
            for (let path of this._dividePaths)
                path.reverse()
        }

    }

    getPath(): { x: number, y: number }[] {
        let divide = this._dividePaths
        let path = []
        for (let _path of divide) {
            for (let i = 0; i <= this._smoothness; i++) {
                path.push(this.bezier(_path, i / this._smoothness))
            }
        }
        return path
    }

    set smoothness(n) {
        this._smoothness = n
    }

    get smoothness() {
        return this._smoothness
    }

    private _dividePath() {
        let segmentPaths = []
        let posArr = this._posArr.concat()
        if (posArr.length > this.ctlPosNum + 1) {
            while (posArr.length) {
                let onePath = []
                while (onePath.length <= this.ctlPosNum && posArr.length) {
                    if (onePath.length != this.ctlPosNum)
                        onePath.push(posArr.shift())
                    else {
                        if (posArr.length > 1)
                            onePath.push(posArr[0])
                        else
                            onePath.push(posArr.shift())
                    }
                }
                segmentPaths.push(onePath)
            }
        } else {
            segmentPaths.push(posArr)
        }
        this._dividePaths = segmentPaths as any
    }

    //阶乘
    private factorial(n) {
        if (n <= 1) {
            return 1;
        }
        let i = 1, temp = 1, sum = 0;
        for (i = 1; i <= n; i++) {
            temp = i * temp;
            sum += temp;
        }
        return sum;
    }

    //获取每个时间单位所在的点
    bezier(posArr, t) {
        if (!posArr || !(posArr instanceof Array)) {
            if (CC_DEBUG) {
                console.error("bezier posArr is unusual");
            }
            return
        }
        if (posArr.length < 2) {
            return { x: posArr[0].x, y: posArr[0].y }
        }
        var x = 0,
            y = 0,
            //控制点数组
            n = posArr.length - 1;
        let tempDir = 0
        posArr.forEach((item, index) => {
            if (!index) {
                tempDir = Math.pow((1 - t), n - index) * Math.pow(t, index)
                x += item.x * tempDir
                y += item.y * tempDir
            } else {
                //factorial为阶乘函数
                let tempDir = this.factorial(n) / this.factorial(index) / this.factorial(n - index) * Math.pow((1 - t), n - index) * Math.pow(t, index)
                x += tempDir * item.x
                y += tempDir * item.y
            }
        })
        return { x, y }
    }
}